package demoMod.anm2editor.core;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import demoMod.anm2editor.fonts.FontKeys;
import demoMod.anm2editor.interfaces.ReloadStringsSubscriber;
import demoMod.anm2editor.localization.LocalizedStrings;
import demoMod.anm2editor.model.Operation;
import demoMod.anm2editor.model.Project;
import demoMod.anm2editor.ui.*;
import demoMod.anm2editor.utils.Preferences;
import demoMod.anm2editor.utils.ReflectionHacks;
import demoMod.gdxform.abstracts.Container;
import demoMod.gdxform.core.EventHooks;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.interfaces.Element;
import demoMod.gdxform.ui.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.Display;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class MainWindow implements ApplicationListener, ReloadStringsSubscriber {
    private SpriteBatch sb;
    private FormManager formManager;
    private static final Logger log = LogManager.getLogger(MainWindow.class);

    @Override
    public void create() {
        log.info("Initializing application...");
        log.info("Loading preferences...");
        Preferences.load();
        log.info("Preferences loaded.");
        int[] resolution = Preferences.getPreferences().getResolution();
        if (resolution != null) {
            if (resolution[0] != Gdx.graphics.getWidth() || resolution[1] != Gdx.graphics.getHeight()) {
                Gdx.graphics.setWindowedMode(resolution[0], resolution[1]);
            }
        }
        String name = ManagementFactory.getRuntimeMXBean().getName();
        String pid = name.split("@")[0];
        log.info("pid is: " + pid);

        sb = new SpriteBatch();
        log.info("Loading fonts...");
        FontKeys.initialize();
        log.info("Fonts loaded.");
        LocalizedStrings.reloadStrings();
        log.info("Loading localized strings...");
        LocalizedStrings.subscribe(this);
        log.info("Localized strings loaded.");
        log.info("Creating windows...");
        formManager = FormManager.getInstance();
        formManager.addContainer(new Timeline());
        log.info("Created timeline.");
        formManager.addContainer(new TrackPane());
        log.info("Created track pane.");
        formManager.addContainer(new AnimationPane());
        log.info("Created animation pane.");
        formManager.addContainer(new EventPane());
        log.info("Created event pane.");
        formManager.addContainer(new StatusBar());
        log.info("Created status bar.");
        new RegionManager();
        log.info("Created region manager.");
        HistoryPanel historyPanel = new HistoryPanel();
        log.info("Created history panel.");
        new ToolBar();
        log.info("Created tool bar.");
        new KeyFramePropertyPanel(FontHelper.getFont(FontKeys.SIM_HEI_14));
        log.info("Created keyframe property panel.");
        formManager.addContainer(new PreviewPane());
        log.info("Created preview pane.");

        loadMenuBar();
        log.info("Created menu bar.");

        Project.loadProject();

        Operation rootOperation = new Operation() {
            @Override
            public void undo() {

            }

            @Override
            public void redo() {

            }
        };
        List<String> menuList = LocalizedStrings.getStrings("MainWindow");
        rootOperation.setName(menuList.get(47));
        historyPanel.setRootOperation(rootOperation);
        log.info("Application started!");
    }

    private void loadMenuBar() {
        HistoryPanel historyPanel = (HistoryPanel) formManager.getContainerById(HistoryPanel.ID);
        GMenuBar menuBar = new GMenuBar();
        menuBar.setId("MainMenuBar");
        menuBar.setBackground(Color.TEAL);
        menuBar.setHeight(22.0F);

        List<String> menuList = LocalizedStrings.getStrings("MainWindow");
        List<String> fileSelectWindowStrings = LocalizedStrings.getStrings("FileSelectWindow");
        GMenuBar.GMenuBarItem fileMenu = new GMenuBar.GMenuBarItem(48, menuBar.getHeight(), menuList.get(0), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public boolean isHotKeyPressed() {
                return Gdx.input.isKeyPressed(Input.Keys.F);
            }
        };

        fileMenu.setSubMenu(() -> {
            GMenuList fileMenuList = new GMenuList();
            fileMenuList.setWidth(200.0F);

            GMenuItem newFile = new GMenuItem(100.0F, fileMenuList.getMenuItemHeight(), menuList.get(1) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    if (!Project.isBlankProject()) {
                        QuestionBox questionBox = new QuestionBox(menuList.get(2), menuList.get(3), FontHelper.getFont(FontKeys.SIM_HEI_14));
                        questionBox.setConfirmCallback(this::createProject);
                    } else {
                        createProject();
                    }
                }

                private void createProject() {
                    GFileSelectWindow fileSelectWindow = new GFileSelectWindow(FontHelper.getFont(FontKeys.SIM_HEI_14));
                    fileSelectWindow.setTitle(menuList.get(4));
                    fileSelectWindow.setConfirmText(fileSelectWindowStrings.get(0));
                    fileSelectWindow.setCancelText(fileSelectWindowStrings.get(1));
                    fileSelectWindow.setBackText(fileSelectWindowStrings.get(2));
                    String path = Preferences.getPreferences().getLastSavePath() == null ? new File("").getAbsolutePath() : Preferences.getPreferences().getLastSavePath();
                    fileSelectWindow.setPath(path);
                    fileSelectWindow.setConfirmCallback((selectedPath, selectedFiles) -> {
                        log.info("Creating a project.");
                        try {
                            Project.currentProject.dispose();
                            Project.clearProject();
                            Project.currentProject = Project.getBlankProject();
                            Project.loadProject();
                            File file = new File(selectedPath);
                            if (file.isDirectory()) {
                                Project.currentProject.setFilePath(selectedPath);
                                Project.currentProject.setFilename("unnamed.anm2");
                            } else {
                                if (!(file.getName().endsWith(".xml") || file.getName().endsWith(".anm2"))) {
                                    file = new File(file.getAbsolutePath() + ".anm2");
                                }
                                if (!file.exists()) {
                                    file.createNewFile();
                                }
                                Project.saveProject(file.getAbsolutePath());
                                Project.currentProject.setFilePath(file.getParentFile().getAbsolutePath());
                                Project.currentProject.setFilename(file.getName());
                            }
                            Display.setTitle("Anm2 Editor - " + Project.currentProject.getFilePath() + File.separator + Project.currentProject.getFilename());
                            Preferences.getPreferences().setLastSavePath(Project.currentProject.getFilePath());
                            Preferences.save();
                            new MessageBox(menuList.get(5), menuList.get(6), FontHelper.getFont(FontKeys.SIM_HEI_14));
                            Operation rootOperation = new Operation() {
                                @Override
                                public void undo() {
                                }

                                @Override
                                public void redo() {
                                }
                            };
                            rootOperation.setName(menuList.get(7));
                            historyPanel.setRootOperation(rootOperation);
                            log.info("Successfully created a project. Location: {}", Project.currentProject.getFilePath() + File.separator + Project.currentProject.getFilename());
                        } catch (Exception e) {
                            new MessageBox(menuList.get(8), menuList.get(9), FontHelper.getFont(FontKeys.SIM_HEI_14));
                            log.error("Create project failed.", e);
                        }
                    });
                }
            };
            GMenuItem open = new GMenuItem(100.0F, fileMenuList.getMenuItemHeight(), menuList.get(10) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    if (!Project.isBlankProject()) {
                        QuestionBox questionBox = new QuestionBox(menuList.get(11), menuList.get(12), FontHelper.getFont(FontKeys.SIM_HEI_14));
                        questionBox.setConfirmCallback(this::openProject);
                    } else {
                        openProject();
                    }
                }

                private void openProject() {
                    GFileSelectWindow fileSelectWindow = new GFileSelectWindow(FontHelper.getFont(FontKeys.SIM_HEI_14));
                    fileSelectWindow.setTitle(menuList.get(13));
                    fileSelectWindow.setConfirmText(fileSelectWindowStrings.get(0));
                    fileSelectWindow.setCancelText(fileSelectWindowStrings.get(1));
                    fileSelectWindow.setBackText(fileSelectWindowStrings.get(2));
                    fileSelectWindow.setFileFilter(file -> file.isDirectory() || file.getName().endsWith(".anm2") || file.getName().endsWith(".xml"));
                    fileSelectWindow.setPath(Preferences.getPreferences().getLastOpenPath() == null ? new File("").getAbsolutePath() : Preferences.getPreferences().getLastOpenPath());
                    fileSelectWindow.setConfirmCallback((path, selectedFiles) -> {
                        if (!selectedFiles.isEmpty()) {
                            log.info("Opening a project.");
                            try {
                                Project.openProject(selectedFiles.get(0));
                                Project.clearProject();
                                Project.loadProject();
                                Display.setTitle("Anm2 Editor - " + selectedFiles.get(0).getAbsolutePath());
                                File file = new File(path);
                                Preferences.getPreferences().setLastOpenPath(file.isDirectory() ? path : file.getParentFile().getAbsolutePath());
                                Preferences.save();
                                Operation rootOperation = new Operation() {
                                    @Override
                                    public void undo() {
                                    }

                                    @Override
                                    public void redo() {
                                    }
                                };
                                rootOperation.setName(menuList.get(14));
                                historyPanel.setRootOperation(rootOperation);
                                log.info("Successfully opened project. Location: {}", selectedFiles.get(0).getAbsolutePath());
                            } catch (Exception e) {
                                new MessageBox(menuList.get(15), menuList.get(16), FontHelper.getFont(FontKeys.SIM_HEI_14));
                                log.error("Open project failed.", e);
                            }
                        }
                    });
                }
            };
            GMenuItem save = new GMenuItem(100.0F, fileMenuList.getMenuItemHeight(), menuList.get(17) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    if (Project.currentProject.getFilePath() == null) {
                        GFileSelectWindow fileSelectWindow = new GFileSelectWindow(FontHelper.getFont(FontKeys.SIM_HEI_14));
                        fileSelectWindow.setTitle(menuList.get(18));
                        fileSelectWindow.setConfirmText(fileSelectWindowStrings.get(0));
                        fileSelectWindow.setCancelText(fileSelectWindowStrings.get(1));
                        fileSelectWindow.setBackText(fileSelectWindowStrings.get(2));
                        String path = Preferences.getPreferences().getLastSavePath() == null ? new File("").getAbsolutePath() : Preferences.getPreferences().getLastSavePath();
                        fileSelectWindow.setPath(path);
                        fileSelectWindow.setConfirmCallback((selectedPath, selectedFiles) -> {
                            log.info("Saving project.");
                            try {
                                Project.saveProject(selectedPath);
                                Preferences.getPreferences().setLastSavePath(new File(selectedPath).getParentFile().getAbsolutePath());
                                Preferences.save();
                                new MessageBox(menuList.get(19), menuList.get(20) + selectedPath, FontHelper.getFont(FontKeys.SIM_HEI_14));
                                log.info("Successfully saved project. Location: {}", selectedFiles.get(0).getAbsolutePath());
                            } catch (Exception e) {
                                new MessageBox(menuList.get(21), menuList.get(22), FontHelper.getFont(FontKeys.SIM_HEI_14));
                                log.error("Save project failed.", e);
                            }
                        });
                    } else {
                        log.info("Saving project.");
                        try {
                            String path = Project.currentProject.getFilePath() + File.separator + Project.currentProject.getFilename();
                            Project.saveProject(path);
                            new MessageBox(menuList.get(19), menuList.get(20) + path, FontHelper.getFont(FontKeys.SIM_HEI_14));
                            log.info("Successfully saved project. Location: {}", path);
                        } catch (Exception e) {
                            new MessageBox(menuList.get(21), menuList.get(22), FontHelper.getFont(FontKeys.SIM_HEI_14));
                            log.error("Save project failed.", e);
                        }
                    }
                }
            };
            GMenuItem saveAs = new GMenuItem(100.0F, fileMenuList.getMenuItemHeight(), menuList.get(23) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    GFileSelectWindow fileSelectWindow = new GFileSelectWindow(FontHelper.getFont(FontKeys.SIM_HEI_14));
                    fileSelectWindow.setTitle(menuList.get(24));
                    fileSelectWindow.setConfirmText(fileSelectWindowStrings.get(0));
                    fileSelectWindow.setCancelText(fileSelectWindowStrings.get(1));
                    fileSelectWindow.setBackText(fileSelectWindowStrings.get(2));
                    String path = Preferences.getPreferences().getLastSavePath();
                    fileSelectWindow.setPath(path == null ? new File("").getAbsolutePath() : path);
                    fileSelectWindow.setConfirmCallback((selectedPath, selectedFiles) -> {
                        try {
                            File file = new File(selectedPath);
                            if (file.isDirectory()) {
                                if (selectedPath.endsWith(File.separator)) {
                                    selectedPath = selectedPath.substring(0, selectedPath.length() - 1);
                                }
                                selectedPath = selectedPath + File.separator + Project.currentProject.getFilename();
                                file = new File(selectedPath);
                                final String savePath = file.getAbsolutePath();
                                if (file.exists()) {
                                    QuestionBox questionBox = new QuestionBox(menuList.get(25), menuList.get(26), FontHelper.getFont(FontKeys.SIM_HEI_14));
                                    questionBox.setConfirmCallback(() -> {
                                        log.info("Saving as another project.");
                                        try {
                                            Project.saveProject(savePath);
                                            Preferences.getPreferences().setLastSavePath(new File(savePath).getParentFile().getAbsolutePath());
                                            Preferences.save();
                                            new MessageBox(menuList.get(27), menuList.get(28) + savePath, FontHelper.getFont(FontKeys.SIM_HEI_14));
                                            log.info("Successfully saved as another project(overwrite). Location: {}", savePath);
                                        } catch (Exception e) {
                                            new MessageBox(menuList.get(29), menuList.get(30), FontHelper.getFont(FontKeys.SIM_HEI_14));
                                            log.error("Save as another project failed.", e);
                                        }
                                    });
                                    return;
                                }
                            } else {
                                if (file.exists()) {
                                    final String savePath = file.getAbsolutePath();
                                    QuestionBox questionBox = new QuestionBox(menuList.get(25), menuList.get(26), FontHelper.getFont(FontKeys.SIM_HEI_14));
                                    questionBox.setConfirmCallback(() -> {
                                        log.info("Saving as another project.");
                                        try {
                                            Project.saveProject(savePath);
                                            Preferences.getPreferences().setLastSavePath(new File(savePath).getParentFile().getAbsolutePath());
                                            Preferences.save();
                                            new MessageBox(menuList.get(27), menuList.get(28) + savePath, FontHelper.getFont(FontKeys.SIM_HEI_14));
                                            log.info("Successfully saved as another project. Location: {}", savePath);
                                        } catch (Exception e) {
                                            new MessageBox(menuList.get(29), menuList.get(30), FontHelper.getFont(FontKeys.SIM_HEI_14));
                                            log.error("Save as another project failed.", e);
                                        }
                                    });
                                    return;
                                }
                            }
                            Project.saveProject(selectedPath);
                            Preferences.getPreferences().setLastSavePath(new File(selectedPath).getParentFile().getAbsolutePath());
                            Preferences.save();
                            new MessageBox(menuList.get(27), menuList.get(28) + selectedPath, FontHelper.getFont(FontKeys.SIM_HEI_14));
                        } catch (Exception e) {
                            new MessageBox(menuList.get(29), menuList.get(30), FontHelper.getFont(FontKeys.SIM_HEI_14));
                            e.printStackTrace();
                        }
                    });
                }
            };
            GMenuItem exit = new GMenuItem(100.0F, fileMenuList.getMenuItemHeight(), menuList.get(53) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    Gdx.app.exit();
                }
            };
            exit.setSplitLine(false);

            fileMenuList.addElement(newFile);
            fileMenuList.addElement(open);
            fileMenuList.addElement(save);
            fileMenuList.addElement(saveAs);
            fileMenuList.addElement(exit);

            return fileMenuList;
        });
        GMenuBar.GMenuBarItem editMenu = new GMenuBar.GMenuBarItem(48, menuBar.getHeight(), menuList.get(31), FontHelper.getFont(FontKeys.SIM_HEI_14));
        editMenu.setSubMenu(() -> {
            GMenuList editMenuList = new GMenuList();
            editMenuList.setWidth(260.0F);

            String undoName = menuList.get(32);
            if (historyPanel.getCurrentOperation() != null) {
                undoName = undoName + " " + historyPanel.getCurrentOperation().getName();
            }
            GMenuItem undo = new GMenuItem(editMenuList.getWidth(), editMenuList.getMenuItemHeight(), undoName, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    log.info("Undo {}", historyPanel.getCurrentOperation().getName());
                    historyPanel.undo(historyPanel.getCurrentOperation().getPrev());
                }
            };
            if (historyPanel.getRootOperation() == historyPanel.getCurrentOperation()) {
                undo.setEnabled(false);
            }

            String redoName = menuList.get(33);
            if (historyPanel.getCurrentOperation() != null && historyPanel.getCurrentOperation().getNext() != null) {
                redoName = redoName + " " + historyPanel.getCurrentOperation().getNext().getName();
            }
            GMenuItem redo = new GMenuItem(editMenuList.getWidth(), editMenuList.getMenuItemHeight(), redoName, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    log.info("Redo {}", historyPanel.getCurrentOperation().getName());
                    historyPanel.redo(historyPanel.getCurrentOperation().getNext());
                }
            };
            if (historyPanel.getCurrentOperation().getNext() == null) {
                redo.setEnabled(false);
            }

            GMenuItem freezeFrame = new GMenuItem(editMenuList.getWidth(), editMenuList.getMenuItemHeight(), menuList.get(52), FontHelper.getFont(FontKeys.SIM_HEI_14));
            freezeFrame.setSubMenu(() -> {
                GMenuList menuList1 = new GMenuList();
                menuList1.setWidth(editMenuList.getWidth());

                GMenuItem bake = new GMenuItem(menuList1.getWidth(), menuList1.getMenuItemHeight(), menuList.get(54), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                    @Override
                    public void onClick() {
                        new BakeWindow(FontHelper.getFont(FontKeys.SIM_HEI_14), ((Timeline)FormManager.getInstance().getContainerById(Timeline.ID)).getCurrentSelectedKeyFrame());
                    }
                };
                if (((Timeline)FormManager.getInstance().getContainerById(Timeline.ID)).getCurrentSelectedTrack() == null) {
                    bake.setEnabled(false);
                }

                GMenuItem pathAnimation = new GMenuItem(menuList1.getWidth(), menuList1.getMenuItemHeight(), menuList.get(55), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                    @Override
                    public void onClick() {
                        new PathEditWindow(FontHelper.getFont(FontKeys.SIM_HEI_14), ((Timeline)FormManager.getInstance().getContainerById(Timeline.ID)).getCurrentSelectedKeyFrame());
                    }
                };
                if (((Timeline)FormManager.getInstance().getContainerById(Timeline.ID)).getCurrentSelectedTrack() == null) {
                    pathAnimation.setEnabled(false);
                }
                pathAnimation.setSplitLine(false);

                menuList1.addElement(bake);
                menuList1.addElement(pathAnimation);

                return menuList1;
            });

            GMenuItem copyKeyframeProperties = new GMenuItem(editMenuList.getWidth(), editMenuList.getMenuItemHeight(), menuList.get(56), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    new CopyKeyframePropertyWindow(FontHelper.getFont(FontKeys.SIM_HEI_14));
                }
            };

            GMenuItem adjustKeyframeProperties = new GMenuItem(editMenuList.getWidth(), editMenuList.getMenuItemHeight(), menuList.get(57), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    new AdjustKeyframePropertyWindow(FontHelper.getFont(FontKeys.SIM_HEI_14));
                }
            };
            adjustKeyframeProperties.setSplitLine(false);
            if (Project.currentProject.getCurrentAnimation() == null) {
                adjustKeyframeProperties.setEnabled(false);
            }

            editMenuList.addElement(undo);
            editMenuList.addElement(redo);
            editMenuList.addElement(freezeFrame);
            editMenuList.addElement(copyKeyframeProperties);
            editMenuList.addElement(adjustKeyframeProperties);

            return editMenuList;
        });

        GMenuBar.GMenuBarItem viewMenu = new GMenuBar.GMenuBarItem(48, menuBar.getHeight(), menuList.get(34), FontHelper.getFont(FontKeys.SIM_HEI_14));

        viewMenu.setSubMenu(() -> {
            GMenuList viewMenuList = new GMenuList();
            viewMenuList.setWidth(200.0F);

            GMenuItem regionManager = new GMenuItem(200.0F, viewMenuList.getMenuItemHeight(), menuList.get(35), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    RegionManager regionManager1 = (RegionManager) formManager.getContainerById(RegionManager.ID);
                    regionManager1.setVisible(!regionManager1.visible());
                }
            };
            GMenuItem keyFrameProperty = new GMenuItem(200.0F, viewMenuList.getMenuItemHeight(), menuList.get(36), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    KeyFramePropertyPanel keyFramePropertyPanel = (KeyFramePropertyPanel) formManager.getContainerById(KeyFramePropertyPanel.ID);
                    keyFramePropertyPanel.setVisible(!keyFramePropertyPanel.visible());
                }
            };
            GMenuItem toolBar = new GMenuItem(200.0F, viewMenuList.getMenuItemHeight(), menuList.get(37), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    ToolBar toolBar1 = (ToolBar) formManager.getContainerById(ToolBar.ID);
                    toolBar1.setVisible(!toolBar1.visible());
                }
            };
            GMenuItem history = new GMenuItem(200.0F, viewMenuList.getMenuItemHeight(), menuList.get(38), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    historyPanel.setVisible(!historyPanel.visible());
                }
            };
            GMenuItem about = new GMenuItem(200.0F, viewMenuList.getMenuItemHeight(), menuList.get(48) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    new AboutWindow();
                }
            };
            about.setSplitLine(false);

            viewMenuList.addElement(regionManager);
            viewMenuList.addElement(keyFrameProperty);
            viewMenuList.addElement(toolBar);
            viewMenuList.addElement(history);
            viewMenuList.addElement(about);

            return viewMenuList;
        });
        GMenuBar.GMenuBarItem optionMenu = new GMenuBar.GMenuBarItem(48, menuBar.getHeight(), menuList.get(39), FontHelper.getFont(FontKeys.SIM_HEI_14));

        optionMenu.setSubMenu(() -> {
            GMenuList optionMenuList = new GMenuList();
            optionMenuList.setWidth(200.0F);

            GMenuItem displayGuides = new GMenuItem(200.0F, optionMenuList.getMenuItemHeight(), menuList.get(40), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    Preferences.getPreferences().setDisplayGuide(!Preferences.getPreferences().displayGuide());
                    Preferences.save();
                }
            };
            GMenuItem screenResolution = new GMenuItem(200.0F, optionMenuList.getMenuItemHeight(), menuList.get(41) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    List<String> screenSize = new ArrayList<>();
                    screenSize.add("800 * 600");
                    screenSize.add("1024 * 768");
                    screenSize.add("1280 * 720");
                    screenSize.add("1440 * 900");
                    screenSize.add("1600 * 900");
                    screenSize.add("1920 * 1080");
                    screenSize.add("3840 * 2160");
                    int index;
                    switch (Gdx.graphics.getWidth() * 1000 + Gdx.graphics.getHeight()) {
                        case 800600:
                        default:
                            index = 0;
                            break;
                        case 1024768:
                            index = 1;
                            break;
                        case 1280720:
                            index = 2;
                            break;
                        case 1440900:
                            index = 3;
                            break;
                        case 1600900:
                            index = 4;
                            break;
                        case 1921080:
                            index = 5;
                            break;
                        case 3842160:
                            index = 6;
                            break;
                    }
                    OptionWindow optionWindow = new OptionWindow(menuList.get(42), screenSize, FontHelper.getFont(FontKeys.SIM_HEI_14), index);
                    optionWindow.setConfirmCallback(i -> {
                        int[] res = new int[2];
                        switch (i) {
                            case 0:
                                res[0] = 800;
                                res[1] = 600;
                                break;
                            case 1:
                                res[0] = 1024;
                                res[1] = 768;
                                break;
                            case 2:
                                res[0] = 1280;
                                res[1] = 720;
                                break;
                            case 3:
                                res[0] = 1440;
                                res[1] = 900;
                                break;
                            case 4:
                                res[0] = 1600;
                                res[1] = 900;
                                break;
                            case 5:
                                res[0] = 1920;
                                res[1] = 1080;
                                break;
                            case 6:
                                res[0] = 3840;
                                res[1] = 2160;
                                break;
                        }
                        Preferences.getPreferences().setResolution(res);
                        Preferences.save();
                        new MessageBox(menuList.get(43), menuList.get(44), FontHelper.getFont(FontKeys.SIM_HEI_14));
                    });
                }
            };
            GMenuItem language = new GMenuItem(200.0F, optionMenuList.getMenuItemHeight(), menuList.get(45) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    List<String> languages = LocalizedStrings.getStrings("Languages");
                    int index = 0;
                    switch (Preferences.getPreferences().getLanguage()) {
                        case "zhs":
                        default:
                            break;
                        case "eng":
                            index = 1;
                            break;
                    }
                    OptionWindow optionWindow = new OptionWindow(menuList.get(46), languages, FontHelper.getFont(FontKeys.SIM_HEI_14), index);
                    optionWindow.setConfirmCallback(i -> {
                        switch (i) {
                            case 0:
                            default:
                                Preferences.getPreferences().setLanguage("zhs");
                                break;
                            case 1:
                                Preferences.getPreferences().setLanguage("eng");
                                break;
                        }
                        Preferences.save();
                        LocalizedStrings.reloadStrings();
                    });
                }
            };
            GMenuItem regionNameOption = new GMenuItem(200.0F, optionMenuList.getMenuItemHeight(), menuList.get(51) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    new RegionOptionWindow();
                }
            };

            GMenuItem maxUndoTimes = new GMenuItem(200.0F, optionMenuList.getMenuItemHeight(), menuList.get(58) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    TextInputWindow textInputWindow = new TextInputWindow(menuList.get(58), Integer.toString(Preferences.getPreferences().getMaxPreservedOperations()), FontHelper.getFont(FontKeys.SIM_HEI_14));
                    textInputWindow.setCharFilter("[0-9]");
                    textInputWindow.setConfirmCallback(undoTimesStr -> {
                        try {
                            int undoTimes = Integer.parseInt(undoTimesStr);
                            if (undoTimes < 3 || undoTimes > 200) {
                                new MessageBox(menuList.get(49), menuList.get(59), FontHelper.getFont(FontKeys.SIM_HEI_14));
                                return;
                            }
                            Preferences.getPreferences().setMaxPreservedOperations(undoTimes);
                            Preferences.save();
                        } catch (NumberFormatException e) {
                            new MessageBox(menuList.get(49), menuList.get(59), FontHelper.getFont(FontKeys.SIM_HEI_14));
                        }
                    });
                }
            };
            maxUndoTimes.setSplitLine(false);

            optionMenuList.addElement(displayGuides);
            optionMenuList.addElement(screenResolution);
            optionMenuList.addElement(language);
            optionMenuList.addElement(regionNameOption);
            optionMenuList.addElement(maxUndoTimes);
            return optionMenuList;
        });

        menuBar.addElement(fileMenu);
        menuBar.addElement(editMenu);
        menuBar.addElement(viewMenu);
        menuBar.addElement(optionMenu);

        formManager.addContainer(menuBar);

        List<String> textFieldStrings = LocalizedStrings.getStrings("TextField");
        GTextField.cutText = textFieldStrings.get(0);
        GTextField.copyText = textFieldStrings.get(1);
        GTextField.pasteText = textFieldStrings.get(2);
        GTextField.selectAllText = textFieldStrings.get(3);
    }

    @Override
    public void resize(int x, int y) {
    }

    @Override
    public void render() {
        try {
            Gdx.gl20.glClearColor(0.16863F, 0.16863F, 0.16863F, 1);
            Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
            formManager.update();
            sb.begin();
            formManager.render(sb);
            sb.end();
        } catch (Exception e) {
            log.error("Exception occurred in render method!", e);
            if (sb.isDrawing()) {
                sb.end();
            }
            processCrash();
        }
    }

    public static void processCrash() {
        FormManager formManager = FormManager.getInstance();
        for (Container<?> container : formManager.getContainerList()) {
            try {
                container.dispose();
            } catch (Throwable ignored) {
            }
        }
        try {
            Field field = FormManager.class.getDeclaredField("containerList");
            field.setAccessible(true);
            List<Container<? extends Element>> containerList = (List<Container<? extends Element>>) field.get(formManager);
            containerList.clear();
        } catch (NoSuchFieldException | IllegalAccessException ex) {
            ex.printStackTrace();
        }
        ReflectionHacks.setPrivate(formManager.getEventHooks(), EventHooks.class, "currentFocusedElement", null);
        List<String> strings = LocalizedStrings.getStrings("MainWindow");
        List<String> fileSelectWindowStrings = LocalizedStrings.getStrings("FileSelectWindow");
        MessageBox questionBox = new MessageBox(strings.get(49), strings.get(50), FontHelper.getFont(FontKeys.SIM_HEI_14));
        questionBox.setConfirmCallback(() -> {
            if (Project.currentProject.getFilePath() == null) {
                GFileSelectWindow fileSelectWindow = new GFileSelectWindow(FontHelper.getFont(FontKeys.SIM_HEI_14));
                fileSelectWindow.setTitle(strings.get(18));
                fileSelectWindow.setConfirmText(fileSelectWindowStrings.get(0));
                fileSelectWindow.setCancelText(fileSelectWindowStrings.get(1));
                fileSelectWindow.setBackText(fileSelectWindowStrings.get(2));
                String path = Preferences.getPreferences().getLastSavePath() == null ? new File("").getAbsolutePath() : Preferences.getPreferences().getLastSavePath();
                fileSelectWindow.setPath(path);
                fileSelectWindow.setConfirmCallback((selectedPath, selectedFiles) -> {
                    try {
                        Project.saveProject(selectedPath);
                        Preferences.getPreferences().setLastSavePath(new File(selectedPath).getParentFile().getAbsolutePath());
                        Preferences.save();
                        Gdx.app.exit();
                    } catch (Exception e1) {
                        new MessageBox(strings.get(21), strings.get(22), FontHelper.getFont(FontKeys.SIM_HEI_14)).setConfirmCallback(() -> Gdx.app.exit());
                        log.error("Save project failed!", e1);
                    }
                });
            } else {
                try {
                    String path = Project.currentProject.getFilePath() + File.separator + Project.currentProject.getFilename();
                    Project.saveProject(path);
                    Gdx.app.exit();
                } catch (Exception e1) {
                    new MessageBox(strings.get(21), strings.get(22), FontHelper.getFont(FontKeys.SIM_HEI_14)).setConfirmCallback(() -> Gdx.app.exit());
                    log.error("Save project failed!", e1);
                }
            }
        });
    }

    @Override
    public void pause() {
        formManager.pause();
    }

    @Override
    public void resume() {
        formManager.resume();
    }

    @Override
    public void dispose() {
        formManager.dispose();
        Project.currentProject.dispose();
        sb.dispose();
    }

    @Override
    public void onReloadStrings() {
        formManager.removeContainer(formManager.getContainerById("MainMenuBar"));
        loadMenuBar();
        List<String> textFieldStrings = LocalizedStrings.getStrings("TextField");
        GTextField.cutText = textFieldStrings.get(0);
        GTextField.copyText = textFieldStrings.get(1);
        GTextField.pasteText = textFieldStrings.get(2);
        GTextField.selectAllText = textFieldStrings.get(3);
    }
}
